package xj.model.uml;

import static xj.model.uml.UMLModelConstants.ROLE_LIFE_LINE;
import static xj.model.uml.UMLModelConstants.ROLE_MESSAGE;
import static xj.model.uml.UMLModelConstants.ROLE_OBJECT;
import static xj.model.uml.UMLModelConstants.ROLE_SEQUENCE_NODE;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import xj.meta.ModelElement;

public class SequenceDiagram extends UMLDiagram {

  public SequenceDiagram() {
    setType(DiagramType.Sequence_Diagram);
  }

  public SequenceDiagram(String name) {
    super(name);
    setType(DiagramType.Sequence_Diagram);
  }

  @Override
  public boolean checkAllowedEdge(ModelElement m) {
    if (m != null) { 
      if (m instanceof LifeLine ||
	  m instanceof UMLMessage) { 
	return true;
      } else if (m instanceof UMLAssociation) { 
	UMLAssociation a = (UMLAssociation) m;
	if (a.getType() == UMLAssociation.AssociationType.Notes_Link) { 
	  return true;
	}
      }
    }       
    return false; 
  }

  @Override
  public boolean checkAllowedNode(ModelElement m) { 
    if (m != null && 
	(m instanceof UMLObject || 
	 m instanceof ExecutionOccurance ||
	 m instanceof SequenceNode ||
	 m instanceof Note)) {
      return true;
    }
    return false; 
  }

  public void addUMLObject(UMLObject o) {
    if (o != null) {
      objects.add(o);
      addOwnedElement(o, ROLE_OBJECT);
    }
  }

  public void removeUMLObject(UMLObject o) {
    if (o != null) {
      objects.remove(o);
      removeOwnedElement(o);
    }
  }

  public List<UMLObject> getUMLObjects() {
    return objects;
  }

  public void addLifeLine(LifeLine o) {
    if (o != null) {
      executions.add(o);
      addOwnedElement(o, ROLE_LIFE_LINE);
    }
  }

  public void removeLifeLine(LifeLine o) {
    if (o != null) {
      executions.remove(o);
      removeOwnedElement(o);
    }
  }

  public List<LifeLine> getLifeLines() {
    return executions;
  }

  public void addUMLMessage(UMLMessage m) {
    if (m != null) {
      messages.add(m);
      addOwnedElement(m, ROLE_MESSAGE);
    }
  }

  public void removeUMLMessage(UMLMessage m) {
    if (m != null) {
      messages.remove(m);
      removeOwnedElement(m);
    }
  }

  public List<UMLMessage> getUMLMessages() {
    return messages;
  }

  public void addSequenceNode(SequenceNode s) {
    if (s != null) {
      nodes.add(s);
      addOwnedElement(s, ROLE_SEQUENCE_NODE);
    }
  }

  public void removeSequenceNode(SequenceNode s) {
    if (s != null) {
      nodes.remove(s);
      removeOwnedElement(s);
    }
  }

  public Set<SequenceNode> getSequenceNodes() {
    return nodes;
  }

  @Override
  public void deconstruct() {
    super.deconstruct();
    objects.clear();
    executions.clear();
    messages.clear();
    nodes.clear();
  }

  @Override
  public void add(ModelElement parent, ModelElement e, Object arg) {
    if (e != null) {
      if (e instanceof UMLObject) {
	addUMLObject((UMLObject) e);
      } else if (e instanceof UMLMessage) {
	addUMLMessage((UMLMessage) e);
      } else if (e instanceof LifeLine) {
	addLifeLine((LifeLine) e);
      } else if (e instanceof ExecutionOccurance) {
	if (parent instanceof LifeLine) {
	  LifeLine line = (LifeLine) parent;
	  line.addExecutionOccurance((ExecutionOccurance) e);
	} else if (parent instanceof ExecutionOccurance) {
	  ExecutionOccurance exec = (ExecutionOccurance) parent;
	  exec.addExecutionOccurance((ExecutionOccurance) e);
	}
      } else if (e instanceof SequenceNode) {
	addSequenceNode((SequenceNode) e);
      } else {
	super.add(parent, e, arg);
      }
    }
  }

  @Override
  public Object clone() throws CloneNotSupportedException {
    SequenceDiagram sd = (SequenceDiagram) super.clone();

    sd.objects = new ArrayList<UMLObject>();
    Iterator<UMLObject> iter1 = objects.iterator();
    while (iter1.hasNext()) {
      UMLObject o = iter1.next();
      sd.addUMLObject((UMLObject) o.clone());
    }

    sd.executions = new ArrayList<LifeLine>();
    Iterator<LifeLine> iter2 = executions.iterator();
    while (iter2.hasNext()) {
      LifeLine o = iter2.next();
      sd.addLifeLine((LifeLine) o.clone());
    }

    sd.messages = new ArrayList<UMLMessage>();
    Iterator<UMLMessage> iter3 = messages.iterator();
    while (iter3.hasNext()) {
      UMLMessage m = iter3.next();
      sd.addUMLMessage((UMLMessage) m.clone());
    }

    sd.nodes = new HashSet<SequenceNode>();
    Iterator<SequenceNode> iter4 = nodes.iterator();
    while (iter4.hasNext()) {
      SequenceNode s = iter4.next();
      sd.addSequenceNode((SequenceNode) s.clone());
    }

    return sd;
  }

  protected List<UMLObject> objects = new ArrayList<UMLObject>();

  protected List<LifeLine> executions = new ArrayList<LifeLine>();

  protected List<UMLMessage> messages = new ArrayList<UMLMessage>();

  protected Set<SequenceNode> nodes = new HashSet<SequenceNode>();

}
